home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 4 / QRZ Ham Radio Callsign Database - Volume 4.iso / files / tcpip / amiga / asrc29p.lha / pop2cli.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-29  |  9.6 KB  |  462 lines

  1. /*
  2.  *    POP2 Client routines.  Originally authored by Mike Stockett
  3.  *      (WA7DYX).
  4.  *    Modified 27 May 1990 by Allen Gwinn (N5CKP) for compatibility
  5.  *      with later releases (NOS0522).
  6.  *    Added into NOS by PA0GRI (and linted into "standard" C)
  7.  *
  8.  *    Some code culled from previous releases of SMTP.
  9.  *
  10.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  11.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  12.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  13.  *    Permission granted for non-commercial copying and use, provided
  14.  *      this notice is retained.
  15.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  16.  *      also rebuilt locking mechanism
  17.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  18.  *    Permission granted for non-commercial copying and use, provided
  19.  *    this notice is retained.
  20.  */
  21. #include <stdio.h>
  22. #include <fcntl.h>
  23. #include <time.h>
  24. #include <setjmp.h>
  25. #ifdef UNIX
  26. #include <sys/types.h>
  27. #endif
  28. #include "global.h"
  29. #ifdef    ANSIPROTO
  30. #include <stdarg.h>
  31. #endif
  32. #include "mbuf.h"
  33. #include "cmdparse.h"
  34. #include "proc.h"
  35. #include "socket.h"
  36. #include "timer.h"
  37. #include "netuser.h"
  38. #include "dirutil.h"
  39. #include "files.h"
  40. #include "pop2.h"
  41. #include "commands.h"
  42.  
  43. extern char Badhost[];
  44.  
  45. /* pop2 client control block */
  46.  
  47. struct pop2_ccb {
  48.     int    socket;        /* socket for this connection */
  49.     char    state;        /* client state */
  50. #define       CALL        0
  51. #define       NMBR        3
  52. #define       SIZE        5
  53. #define       XFER        8
  54. #define       EXIT        10
  55.     char    buf[BUF_LEN],    /* tcp input buffer */
  56.         count;        /* input buffer length */
  57.     int    folder_len;    /* number of msgs in current folder */
  58.     long    msg_len;    /* length of current msg */
  59.     int    msg_num;    /* current message number */
  60. } *ccb;
  61.  
  62. #define NULLCCB        (struct pop2_ccb *)0
  63.  
  64. char notdefyet[] = "%s NOT defined yet\n";
  65.  
  66. static int pop2quiet = 0;
  67.  
  68. static struct timer  pop2cli_t;
  69. static int32 mailhost;
  70. static char    mailbox_name[10],
  71.         mailbox_pathname[BUF_LEN],
  72.         username[20],
  73.         password[20],
  74.         Workfile_name[] ="mbox.pop2";
  75.  
  76. static int domailbox __ARGS((int argc,char *argv[],void *p));
  77. static int domailhost __ARGS((int argc,char *argv[],void *p));
  78. static int douserdata __ARGS((int argc,char *argv[],void *p));
  79. static int doquiet __ARGS((int argc,char *argv[],void *p));
  80. static int dotimer __ARGS((int argc,char *argv[],void *p));
  81. static struct pop2_ccb     *new_ccb __ARGS((void));
  82. static void delete_ccb __ARGS((void));
  83. static void pop2_send __ARGS((int unused,void *cb1,void *p));
  84. static int pop2kick __ARGS((int argc,char *argv[],void *p));
  85.  
  86. static struct cmds pop2cmds[] = {
  87.     "mailbox",    domailbox,    0,    0,    NULLCHAR,
  88.     "mailhost",    domailhost,    0,    0,    NULLCHAR,
  89.     "kick",        pop2kick,    0,    0,    NULLCHAR,
  90.     "quiet",    doquiet,    0,    0,    NULLCHAR,
  91.     "timer",    dotimer,    0,    0,    NULLCHAR,
  92.     "userdata",    douserdata,    0,    0,    NULLCHAR,
  93.     NULLCHAR,
  94. };
  95.  
  96.  
  97. /* Command string specifications */
  98.  
  99. static char ackd_cmd[] = "ACKD\n",
  100. #ifdef POP2_FOLDERS
  101.     fold_cmd[] = "FOLD %s\n",
  102. #endif
  103.     login_cmd[] = "HELO %s %s\n",
  104. /*      nack_cmd[]      = "NACK\n",     /* Not implemented */
  105.     quit_cmd[]      = "QUIT\n",
  106.     read_cur_cmd[]  = "READ\n",
  107.     retr_cmd[]      = "RETR\n";
  108.  
  109. /* Response string keys */
  110.  
  111. static char *greeting_rsp  = "+ POP2 ";
  112.  
  113. FILE    *fd;
  114. #define    NULLFILE    (FILE *)0
  115.  
  116. int dopop2(argc,argv,p)
  117. int argc;
  118. char *argv[];
  119. void *p;
  120. {
  121.     return subcmd(pop2cmds,argc,argv,p);
  122. }
  123.  
  124. static int domailbox(argc,argv,p) 
  125. int argc;
  126. char *argv[];
  127. void *p;
  128. {
  129.     if(argc < 2) {
  130.         if(mailbox_name[0] == '\0')
  131.             tprintf(notdefyet, "mailbox");
  132.         else
  133.             tprintf("%s\n",mailbox_name);
  134.     } else {
  135.         strncpy(mailbox_name,argv[1],10);
  136.     }
  137.  
  138.     return 0;
  139. }
  140.  
  141. static int domailhost(argc,argv,p)
  142. int argc;
  143. char *argv[];
  144. void *p;
  145. {
  146.     int32 n;
  147.  
  148.     if(argc < 2) {
  149.         tprintf("%s\n",inet_ntoa(mailhost));
  150.     } else
  151.         if((n = resolve(argv[1])) == 0) {
  152.             tprintf(Badhost,argv[1]);
  153.             return 1;
  154.         } else
  155.             mailhost = n;
  156.  
  157.     return 0;
  158. }
  159.  
  160. static int doquiet(argc,argv,p)
  161. int argc;
  162. char *argv[];
  163. void *p;
  164. {
  165.     return setbool(&pop2quiet,"pop2 quiet",argc,argv);
  166. }
  167.  
  168. static int douserdata(argc,argv,p)
  169. int argc;
  170. char *argv[];
  171. void *p;
  172. {
  173.     if (argc < 2)
  174.         tprintf("%s\n",username);
  175.     else if (argc != 3) {
  176.         tprintf("Usage: pop2 user <username> <password>\n");
  177.         return 1;
  178.     } else {
  179.         sscanf(argv[1],"%18s",username);
  180.         sscanf(argv[2],"%18s",password);
  181.     }
  182.  
  183.     return 0;
  184. }
  185.  
  186. /* Set scan interval */
  187.  
  188. static int dotimer(argc,argv,p)
  189. int argc;
  190. char *argv[];
  191. void *p;
  192. {
  193.     int pop2tick();
  194.  
  195.  
  196.     if(argc < 2) {
  197.         tprintf("%lu/%lu\n",
  198.                (pop2cli_t.start - pop2cli_t.count)/(1000/MSPTICK),
  199.                pop2cli_t.start/(1000/MSPTICK));
  200.         return 0;
  201.     }
  202.  
  203.     pop2cli_t.func  = (void (*)())pop2tick;          /* what to call on timeout */
  204.     pop2cli_t.arg   = NULL;                /* dummy value */
  205.     pop2cli_t.start = atol(argv[1])*(1000/MSPTICK);    /* set timer duration */
  206.     start_timer(&pop2cli_t);                /* and fire it up */
  207.     return 0;
  208. }
  209.  
  210. static int pop2kick(argc,argv,p)
  211. int argc;
  212. char *argv[];
  213. void *p;
  214. {
  215.     pop2tick(NULL);
  216.     return 0;
  217. }
  218.  
  219. int pop2tick(t)
  220. void *t;
  221. {
  222.     if (ccb == NULLCCB) {
  223.  
  224.         /* Don't start if any of the required parameters have not been specified */
  225.  
  226.         if (mailhost == 0) {
  227.             tprintf(notdefyet, "mailhost");
  228.             return 0;
  229.         }
  230.  
  231.         if (mailbox_name[0] == '\0') {
  232.             tprintf(notdefyet, "mailbox");
  233.             return 0;
  234.         }
  235.  
  236.         if (username[0] == '\0') {
  237.             tprintf(notdefyet, "username");
  238.             return 0;
  239.         }
  240.  
  241.         if (password[0] == '\0') {
  242.             tprintf(" Unknown password\n");
  243.             return 0;
  244.         }
  245.  
  246.         if ((ccb = new_ccb()) == NULLCCB) {
  247.             fprintf(stderr,"*** Unable to allocate CCB");
  248.             return 0;
  249.         }
  250.  
  251.         newproc("Auto-POP2 Client",1024,pop2_send,0,ccb,NULL);
  252.     }
  253.  
  254.     /* Restart timer */
  255.  
  256.     start_timer(&pop2cli_t);
  257.     return 0;
  258. }
  259.  
  260. /* this is the master state machine that handles a single SMTP transaction */
  261. /* it is called with a queue of jobs for a particular host. */
  262.  
  263. static void pop2_send(unused,cb1,p) 
  264. int unused;
  265. void *cb1;
  266. void *p;
  267. {
  268.     char *cp;
  269.     struct sockaddr_in fsocket;
  270.     struct pop2_ccb    *ccb;
  271.     void pop2_csm(struct pop2_ccb *);
  272.     void quit_session(struct pop2_ccb *);
  273.  
  274.     ccb = (struct pop2_ccb *)cb1;
  275.     fsocket.sin_family = AF_INET;
  276.     fsocket.sin_addr.s_addr = mailhost;
  277.     fsocket.sin_port = IPPORT_POP2;
  278.  
  279.     ccb->socket = socket(AF_INET,SOCK_STREAM,0);
  280.  
  281.     ccb->state = CALL;
  282.  
  283.     if (connect(ccb->socket,(char *)&fsocket,SOCKSIZE) == 0) {
  284.         mainlog(ccb->socket,"Connected to mailhost %s", inet_ntoa(mailhost));
  285.     } else {
  286.         cp = sockerr(ccb->socket);
  287.         mainlog(ccb->socket,"Connect to mailhost %s failed: %s", inet_ntoa(mailhost),
  288.             (cp != NULLCHAR)? cp: "");
  289.     }
  290.  
  291.     while(1) {
  292.         if (recvline(ccb->socket,ccb->buf,BUF_LEN) == -1)
  293.             goto quit;
  294.  
  295.         rip(ccb->buf);
  296.         pop2_csm(ccb);
  297.         if (ccb->state == EXIT)
  298.             goto quit;
  299.     }
  300. quit:
  301.     mainlog(ccb->socket,"Connection closed to mailhost %s", inet_ntoa(mailhost));
  302.     (void) close_s(ccb->socket);
  303.     if (fd != NULLFILE)
  304.         fclose(fd);
  305.     delete_ccb();
  306. }
  307.  
  308. /* free the message struct and data */
  309.  
  310. static void delete_ccb()
  311. {
  312.     if (ccb == NULLCCB)
  313.         return;
  314.  
  315.     free((char *)ccb);
  316.     ccb = NULLCCB;
  317. }
  318.  
  319. /* create a new  pop2 control block */
  320.  
  321. static struct pop2_ccb *new_ccb()
  322. {
  323.     register struct pop2_ccb *ccb;
  324.  
  325.     if ((ccb = (struct pop2_ccb *) callocw(1,sizeof(struct pop2_ccb))) == NULLCCB)
  326.         return(NULLCCB);
  327.     return(ccb);
  328. }
  329.  
  330. /* ---------------------- pop2 client code starts here --------------------- */
  331.  
  332. void pop2_csm(ccb)
  333. struct pop2_ccb    *ccb;
  334. {
  335.     FILE *mf;
  336.  
  337.     int mlock (char *,char *);
  338.     int rmlock (char * ,char *);
  339.     /* int mlock __ARGS((char *dir,char *id));   */
  340.     /* int rmlock __ARGS((char *dir,char *id));   */
  341.  
  342.  
  343.     switch(ccb->state) {
  344.     case CALL:
  345.         if (strncmp(ccb->buf,greeting_rsp,strlen(greeting_rsp)) == 0) {
  346.              (void)usprintf(ccb->socket,login_cmd,username,password);
  347.             ccb->state = NMBR;
  348.         } else
  349.             (void) quit_session(ccb);
  350.         break;
  351.  
  352.     case NMBR:
  353.  
  354.         switch (ccb->buf[0]) {
  355.         case '#':
  356.             if ((fd = fopen(Workfile_name,"a+")) == NULLFILE) {
  357.                 perror("Unable to open work file");
  358.                 quit_session(ccb);
  359.                 return;
  360.             }
  361.  
  362.             fseek(fd,0,0);
  363.             ccb->folder_len = atoi(&(ccb->buf[1]));
  364.             (void)usprintf(ccb->socket,read_cur_cmd);
  365.             ccb->state = SIZE;
  366.             break;
  367.  
  368.         case '+':
  369.  
  370.             /* If there is no mail (the only time we get a "+"
  371.              * response back at this stage of the game),
  372.              * then just close out the connection, because
  373.              * there is nothing more to do!! */
  374.  
  375.         default:
  376.             quit_session(ccb);
  377.             break;
  378.         }
  379.     break;
  380.  
  381.     case SIZE:
  382.         if (ccb->buf[0] == '=') {
  383.             ccb->msg_len = atol(&(ccb->buf[1]));
  384.             if (ccb->msg_len > 0) {
  385.                 (void)usprintf(ccb->socket,retr_cmd);
  386.  
  387.                 ccb->state = XFER;
  388.             } else {
  389.                 mainlog(ccb->socket,"pop2 client retrieved %d messages",
  390.                         ccb->folder_len);
  391.  
  392.                 /* All done, so do local cleanup */
  393.  
  394.                 if (mlock(Mailspool,mailbox_name)) {
  395.                     tprintf("\n*** Local mailbox locked, new mail in file %s\n",
  396.                          Workfile_name);
  397.                     quit_session(ccb);
  398.                     return;
  399.                 }
  400.  
  401.                 sprintf(mailbox_pathname,"%s/%s.txt",Mailspool,
  402.                     mailbox_name);
  403.                 if ((mf = fopen(mailbox_pathname,"a+")) == NULL) {
  404.                     tprintf("\n*** Unable to open local mailbox, new mail in file %s\n",
  405.                            Workfile_name);
  406.                     quit_session(ccb);
  407.                     return;
  408.                 }
  409.  
  410.                 fseek(fd,0,0);
  411.  
  412.                 while (!feof(fd)) {
  413.                     if(fgets(ccb->buf,BUF_LEN,fd) != NULLCHAR) {
  414.                         fputs(ccb->buf,mf);
  415.                     }
  416.                 }
  417.                 fclose(mf);
  418.                 fclose(fd);
  419.                 fd = NULL;
  420.                 printf("\a\x1b[32mNew mail arrived for '\x1b[33m%s\x1b[32m' from mailhost <\x1b[33m%s\x1b[32m>%c\x1b[0m\n",
  421.                     mailbox_name, inet_ntoa(mailhost),
  422.                     pop2quiet ? ' ' : '\007');
  423.                 rmlock(Mailspool,mailbox_name);
  424.                 unlink(Workfile_name);
  425.                 quit_session(ccb);
  426.             }
  427.         } else
  428.             quit_session(ccb);
  429.         break;
  430.  
  431.         case XFER:
  432.             fprintf(fd,"%s\n",ccb->buf);
  433.  
  434.             ccb->msg_len -= (long)(strlen(ccb->buf)+2);    /* Add CRLF */
  435.  
  436.             if (ccb->msg_len > 0)
  437.                 return;
  438.  
  439.             (void)usprintf(ccb->socket,ackd_cmd);
  440.  
  441.             ccb->msg_num++;
  442.             ccb->state = SIZE;
  443.             break;
  444.  
  445.         case EXIT:
  446.             if (fd != NULLFILE)
  447.                 fclose(fd);
  448.             break;
  449.  
  450.         default:
  451.             break;
  452.     }
  453. }
  454.  
  455. void quit_session(ccb)
  456. struct pop2_ccb    *ccb;
  457. {
  458.     (void)usprintf(ccb->socket,quit_cmd);
  459.  
  460.     ccb->state  = EXIT;
  461. }
  462.